package com.atguigu.study.aspect;

import com.atguigu.study.annotations.MyRedisCache;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import org.aspectj.lang.reflect.MethodSignature;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
@Component
@Aspect
@Slf4j
public class MyRedisCacheAspect {
    @Resource
    private RedisTemplate redisTemplate;
    @Resource
    private RabbitTemplate rabbitTemplate;

    //配置织入点
    @Pointcut("@annotation(com.atguigu.study.annotations.MyRedisCache)")
    public void cachePointCut() {
    }

    @Around("cachePointCut()")
    public Object doCache(ProceedingJoinPoint joinPoint) {
        Object result = null;



        try {
            //1 获得重载后的方法名
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();


            //2 确定方法名后获得该方法上面配置的注解标签MyRedisCache
            MyRedisCache myRedisCacheAnnotation = method.getAnnotation(MyRedisCache.class);


            //3 拿到了MyRedisCache这个注解标签，获得该注解上面配置的参数进行封装和调用
            String keyPrefix = myRedisCacheAnnotation.keyPrefix();
            String matchValueSpringEL = myRedisCacheAnnotation.matchValue();


            //4 SpringEL 解析器
            ExpressionParser parser = new SpelExpressionParser();
            Expression expression = parser.parseExpression(matchValueSpringEL);//#id
            EvaluationContext context = new StandardEvaluationContext();


            //5 使用反射获得方法里面的形参信息
            Object[] args = joinPoint.getArgs();
            Parameter[] parameterNames = method.getParameters();
            for (int i = 0; i < parameterNames.length; i++) {
                System.out.println("获得方法里参数名和值: " + parameterNames[i].getName() + "\t" + args[i].toString());
                context.setVariable(parameterNames[i].getName(), args[i].toString());
            }


            //6 通过上述，拼接redis的最终key形式
            String key = keyPrefix + ":" + expression.getValue(context).toString();
            System.out.println("------拼接redis的最终key形式: " + key);


            //7 先去redis里面查询看有没有
            result = redisTemplate.opsForValue().get(key);
            if (result != null) {
                System.out.println("------redis里面有，我直接返回结果不再打扰mysql: " + result);
                return result;
            }

        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }

        return result;
    }
}
